package com.baizhi.cmfz.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Configuration
@Aspect
public class AspectCache {
	private Logger logger = LoggerFactory.getLogger(AspectCache.class);

	@Autowired
	private RedisTemplate redisTemplate;


	/**
	 *
	 * 在执行完查询操作后添加缓存，值针对于添加了AddCacheAnnotation的注解
	 * 先判断其有没有缓存，如果没有，去数据库中查找，之后将其放入redis的缓存中
	 * 如果有，把缓存的结果返回
	 * @param joinPoint 连接对象
	 * @return
	 */

	@Around("@annotation(com.baizhi.cmfz.annotation.AddCacheAnnotation)")
	public Object addCache(ProceedingJoinPoint joinPoint){
//		获取类名，存储到redis 的hash组的key
		String name = joinPoint.getTarget().getClass().getName();
//		获取方法名+形参的值+拼接成新的字符串
		StringBuilder stringBuilder = new StringBuilder();
		String methodName = joinPoint.getSignature().getName();
		stringBuilder.append(methodName);
		Object[] args = joinPoint.getArgs();
		for (Object i : args){
			stringBuilder.append(i);
		}
//		要存储到redis的中的hash组的filekey
		String hashKey = stringBuilder.toString();

//		通过redis中读取数据，如果能读到，那么将读到的结果返回
//		如果读不到，那么去数据库中查询并将结果放入redis中
//		得到操作hash组的连接

		HashOperations hashOperations = redisTemplate.opsForHash();
		Object result = hashOperations.get(name, hashKey);
		if(result==null){
//			打印日志
			logger.debug("查询数据库");
//			放行
			try {
//				得到查询结果，将结果封装在map中；
				result = joinPoint.proceed();
				Map map = new HashMap();
				map.put(hashKey,result);
//				将数据缓存到redis
				hashOperations.putAll(name,map);
//				设置缓存存在的时间 为60秒

				redisTemplate.expire(name,60, TimeUnit.SECONDS);

			} catch (Throwable throwable) {
				throwable.printStackTrace();
//				异常发生之后打印异常信息的同时，打印日志
				logger.error("产生异常可能是查询数据库时产生的，也可能时放入redis时产生的异常");
			}

		}else{
			logger.debug("读取缓存数据");
		}

		return result;
	}



	/**
	 * 删除缓存，使用aop的方法将注解了指定注解的方法执行之间删除对应的缓存
	 * 一般用在增删改的方法上
	 */
	@Before("@annotation(com.baizhi.cmfz.annotation.DeleteCahceAnnotation)")
	public void deleteCache(JoinPoint joinPoint){
		logger.debug("删除缓存");
//		获得类名
		String name = joinPoint.getTarget().getClass().getName();
		logger.debug("删除的类名对应的缓存"+name);
		redisTemplate.delete(name);

	}
}
